import { isOverlap } from '@ibiz-template/core';
import {
  calcLayoutHeightWidth,
  PanelNotifyState,
  verifyPanelGroupLogic,
  IPanelItemController,
  IPanelController,
  IPanelDataContainerController,
  calcDynaClass,
} from '@ibiz-template/runtime';
import { IPanelItem } from '@ibiz/model-core';
import { useNamespace } from '@ibiz-template/vue3-util';
import { PanelItemState } from './panel-item.state';
import { PanelController } from './panel.controller';

export class PanelItemController<T extends IPanelItem = IPanelItem>
  implements IPanelItemController
{
  /**
   * 面板项状态
   *
   * @author chitanda
   * @date 2023-01-04 09:01:04
   * @type {PanelItemState}
   */
  state: PanelItemState;

  /**
   * 数据父容器
   * @author lxm
   * @date 2023-07-15 11:35:18
   * @readonly
   * @type {(IPanelController | IPanelDataContainerController)}
   */
  get dataParent(): IPanelController | IPanelDataContainerController {
    return this.findDataParent(this);
  }

  /**
   * 父容器数据对象数据
   * @author lxm
   * @date 2023-07-15 01:33:58
   * @readonly
   * @type {IData}
   */
  get data(): IData {
    return this.dataParent.data;
  }

  /**
   * 获取容器类名集合
   * @author lxm
   * @date 2023-08-02 06:06:12
   * @readonly
   * @type {string[]}
   */
  get containerClass(): string[] {
    return [...this.state.class.container, ...this.state.class.containerDyna];
  }

  /**
   * 获取标题类名集合
   * @author lxm
   * @date 2023-08-02 06:16:48
   * @readonly
   * @type {string[]}
   */
  get labelClass(): string[] {
    return [...this.state.class.label, ...this.state.class.labelDyna];
  }

  /**
   * Creates an instance of PanelItemController.
   * @author lxm
   * @date 2023-04-27 06:37:12
   * @param {T} model 面板成员模型
   * @param {PanelController} panel 面板控制器
   * @param {PanelItemController} [parent] 父容器控制器
   */
  constructor(
    public readonly model: T,
    public readonly panel: PanelController,
    public readonly parent?: PanelItemController,
  ) {
    this.state = this.createState();
  }

  /**
   * 子类不可覆盖或重写此方法，在 init 时需要重写的使用 onInit 方法。
   *
   * @author lxm
   * @date 2022-08-18 22:08:30
   * @returns {*}  {Promise<void>}
   */
  async init(): Promise<void> {
    await this.onInit();
  }

  protected async onInit(): Promise<void> {
    // 初始化布局参数
    const { layoutPos, itemType, sysCss, labelSysCss } = this.model;

    // 初始化高宽
    if (layoutPos) {
      const { width, height } = calcLayoutHeightWidth(layoutPos);
      this.state.layout.width = `${width}`;
      this.state.layout.height = `${height}`;
    }

    // 给col添加各自类型的类名
    const ns = useNamespace('panel-col');
    this.state.layout.extraClass.push(ns.m(itemType!.toLowerCase()));

    if (sysCss?.cssName) {
      this.state.class.container.push(sysCss.cssName);
    }

    if (labelSysCss?.cssName) {
      this.state.class.label.push(labelSysCss.cssName);
    }
  }

  /**
   * 创建面板状态对象
   *
   * @author chitanda
   * @date 2023-01-04 10:01:00
   * @protected
   * @return {*}  {PanelItemState}
   */
  protected createState(): PanelItemState {
    return new PanelItemState(this.parent?.state);
  }

  /**
   * 面板数据变更通知(由面板控制器调用)
   *
   * @author lxm
   * @date 2022-09-20 18:09:56
   * @param {string[]} names
   */
  dataChangeNotify(names: string[]): void {
    // 计算动态控制逻辑
    this.calcDynamicLogic(names);

    // 计算动态样式表
    this.calcDynaClass(this.data);
  }

  /**
   * 面板状态变更通知
   *
   * @author lxm
   * @date 2022-09-20 18:09:07
   */
  panelStateNotify(_state: PanelNotifyState): void {
    // 计算动态控制逻辑
    this.calcDynamicLogic([], true);

    // 计算动态样式表
    this.calcDynaClass(this.data);
  }

  /**
   * 计算动态逻辑
   *
   * @author lxm
   * @date 2023-02-13 09:42:07
   * @protected
   * @param {string[]} names 变更的属性集合
   * @param {boolean} [mustCalc=false] 是否强制计算一遍动态逻辑
   * @returns {*}  {void}
   * @memberof PanelItemController
   */
  protected calcDynamicLogic(names: string[], mustCalc: boolean = false): void {
    // 逻辑优化，当父容器存在且为不显示时，不去计算自己的动态逻辑
    if (this.parent && !this.parent.state.visible) {
      return;
    }

    // 根据自身的动态逻辑计算
    this.model.panelItemGroupLogics?.forEach(logic => {
      const relatedNames = logic.relatedItemNames || [];
      // name是动态逻辑涉及到的时或state存在时
      if (mustCalc || isOverlap(relatedNames, names)) {
        try {
          const ok = verifyPanelGroupLogic(this.panel.data, logic);
          switch (logic.logicCat) {
            // 动态空输入，不满足则必填
            case 'ITEMBLANK':
              this.state.required = !ok;
              break;
            // 动态启用，满足则启用
            case 'ITEMENABLE':
              this.state.disabled = !ok;
              break;
            // 动态显示，满足则显示
            case 'PANELVISIBLE':
              this.state.visible = ok;
              break;
            default:
          }
        } catch (error) {
          ibiz.log.error(error);
        }
      }
    });
  }

  /**
   * 找到指定成员的数据父容器
   * @author lxm
   * @date 2023-07-15 11:26:49
   * @param {IPanelItemController} panel
   * @return {*}  {(IPanelController | IPanelDataContainerController)}
   */
  findDataParent(
    panel: IPanelItemController,
  ): IPanelController | IPanelDataContainerController {
    const parent = panel.parent;
    if (!parent) {
      return panel.panel;
    }
    if (parent.isDataContainer) {
      return parent as IPanelDataContainerController;
    }
    return this.findDataParent(parent);
  }

  /**
   * 计算动态样式表
   * @author lxm
   * @date 2023-08-02 06:15:08
   * @param {IData} data
   */
  protected calcDynaClass(data: IData): void {
    if (this.model.dynaClass) {
      const dynaClass = calcDynaClass(this.model.dynaClass, data);
      if (dynaClass.length) {
        this.state.class.containerDyna = dynaClass;
      }
    }
    if (this.model.labelDynaClass) {
      const dynaClass = calcDynaClass(this.model.labelDynaClass, data);
      if (dynaClass.length) {
        this.state.class.labelDyna = dynaClass;
      }
    }
  }
}
